#ifdef _WIN32
#include <windows.h>
#endif

#include <new> // 用于 std::hardware_destructive_interference_size
#include <vector>
#include <thread>
#include <atomic>
#include <cassert>
#include <iostream>
#include <algorithm>
#include <functional>

// 原子变量与非原子变量实验
// 这个例子里面的原子操作，关心且只关心自己
namespace CountNumberExample {
	constexpr unsigned int CountLimit	= 1000000;
	constexpr unsigned int ThreadNum	= 2;

	namespace Raw{
		long long Result = 0;
		void Func(int ThreadId, unsigned int N) {
			for (volatile unsigned int i = 0; i < N; i++) {
				Result++;
			}
		}
	}
	namespace Atomic{
#ifdef _WIN32
		LONG64 Result = 0;
#else
		long long Result = 0;
#endif
		void Func(int ThreadId, unsigned int N) {
#ifdef _WIN32
			for (volatile unsigned int i = 0; i < N; i++) {
				InterlockedIncrement64(&Result);
			}
#endif
		}
	}
	namespace StdAtomic{
		std::atomic<long long> Result(0);
		void Func(int ThreadId, unsigned int N) {
			for (volatile unsigned int i = 0; i < N; i++) {
				Result.fetch_add(1);
			}
		}
	}

#define Test(Namespace) { \
	using namespace Namespace; \
	std::thread RealThread[ThreadNum];\
	for (int i = 0; i < ThreadNum; i++) {\
	RealThread[i] = std::thread(Func, i, CountLimit / ThreadNum);\
	}\
	for (int i = 0; i < ThreadNum; i++) {\
		RealThread[i].join();\
	}\
	std::cout << "Result: " << Result << std::endl;\
}

	void Main() {
		Test(Raw);
		Test(Atomic);
		Test(StdAtomic);
	}
}

// 注：这个例子在本人测试过程中，x86环境无法复现
// 原子变量的memory barrier主要是提供给周边非原子变量同步使用
// release保证前面的写入都完成了，"打包"发送没问题
// acquire保证后面的读取还没发生，"打包"读取没问题
namespace MemoryBarrierExample {
	// ===== 周边变量 (非原子) =====
	// 这是我们要同步的普通数据
	std::string g_payload;
	int         g_payload_id = 0;
	// ===== 用于通信的信道 (原子) =====
	// 这个原子变量本身的值不重要，它只作为一个信号
	std::atomic<bool> g_ready = {false};

	std::atomic<long long> ErrorCounter(0);

	// 生产者线程
	template<std::memory_order StoreMemoryOrder>
	void producer() {
		// 写入周边变量 (普通内存操作)
		g_payload = "Hello, from Producer!";
		g_payload_id = 42;

		g_ready.store(true, StoreMemoryOrder);
	}

	// 消费者线程
	template<std::memory_order LoadMemoryOrder>
	void consumer() {
		// 1. 等待“就绪”信号 (普通原子操作)
		while (!g_ready.load(LoadMemoryOrder)) {
			// 自旋等待
		}
		// 2. 读取周边变量 (普通内存操作)
		// 由于屏障的保证，这里的读取是安全的，并且一定能读到生产者写入的新值。这里必须得Cache住现场
		int 		local_var	= g_payload_id;
		std::string local_str 	= g_payload;
		if (local_var != 42 || local_str != "Hello, from Producer!") {
			ErrorCounter.fetch_add(1, std::memory_order_relaxed);
			std::cout << "g_payload_id: " << local_var << std::endl << "g_payload: " << local_str << std::endl;
		}
	}

	template<std::memory_order StoreMemoryOrder, std::memory_order LoadMemoryOrder>
	void TestFuncTemplate() {
		ErrorCounter.store(0, std::memory_order_seq_cst);
		for (unsigned int i = 0; i < 1000000; i++) {
			g_payload 		= "";
			g_payload_id 	= 0;
			g_ready.store(false, std::memory_order_seq_cst);

			std::thread t1(producer<StoreMemoryOrder>);
			std::thread t2(consumer<LoadMemoryOrder>);

			t1.join();
			t2.join();
		}
		std::cout << "[" << LoadMemoryOrder << " " << StoreMemoryOrder << "] Error Num : " << ErrorCounter.load(std::memory_order_relaxed) << std::endl;
	}

	int Main() {
		TestFuncTemplate<std::memory_order_relaxed, std::memory_order_relaxed>();
		TestFuncTemplate<std::memory_order_release, std::memory_order_acquire>();
		return 0;
	}
}

// 注：这个例子在本人测试过程中，x86环境无法复现，引用AI的话
// 核心教训
// 你的单元测试结果，完美地诠释了为什么并发编程如此困难：
// 你必须为“标准”编程，而不是为“你碰巧在用的那个平台”编程。
// 今天你写的能在你的 Intel i7 上完美运行的代码，明天在新的苹果 M 系列芯片 (ARM) 或某个云服务器 CPU 上编译时，就可能因为依赖了 x86 的强内存模型而神秘地崩溃。
// 所以，即使你的测试无法复现错误，也请相信理论：对于这个互斥算法，release/acquire 是不够的，从可移植性和正确性的角度出发，必须使用 seq_cst。
namespace MemoryOrderExample {
	std::atomic<bool> flag_A = {false};
	std::atomic<bool> flag_B = {false};

	// 使用一个原子变量来记录谁赢了，0代表还没结果，1代表A赢，2代表B赢，3代表两个都进去了（错误！）
	std::atomic<int> winner = {0}; 

	template<std::memory_order StoreMemoryOrder, std::memory_order LoadMemoryOrder>
	void ThreadATemplate() {
		// 1. 举起我自己的旗子，告诉别人“我要进”
		flag_A.store(true, /* MEMORY_ORDER_1 */StoreMemoryOrder);
		// 2. 检查对方的旗子
		if (!flag_B.load(/* MEMORY_ORDER_2 */LoadMemoryOrder)) {
			// 对方没举旗，我赢了！
			winner.store(1, StoreMemoryOrder);
		}
	}
	template<std::memory_order StoreMemoryOrder, std::memory_order LoadMemoryOrder>
	void ThreadBTemplate() {
		// 1. 举起我自己的旗子
		flag_B.store(true, /* MEMORY_ORDER_1 */StoreMemoryOrder);
		// 2. 检查对方的旗子
		if (!flag_A.load(/* MEMORY_ORDER_2 */LoadMemoryOrder)) {
			// 对方没举旗，我赢了！
			// 如果B也赢了，把winner改成3，表示出错了
			int local_var = winner.load(LoadMemoryOrder);
			if (local_var == 1) {
				winner.store(3, StoreMemoryOrder);
				// std::cout << local_var << std::endl;
			}
			else winner.store(2, StoreMemoryOrder);
		}
	}

	template<std::memory_order StoreMemoryOrder, std::memory_order LoadMemoryOrder>
	void TestFuncTemplate() {
		uint32_t ErrorCounter = 0;

		for (int i = 0; i < 1000000; i++) {
			winner.store(0, std::memory_order_seq_cst);
			flag_A.store(false, std::memory_order_seq_cst);
			flag_B.store(false, std::memory_order_seq_cst);

			auto thread1 = std::thread(ThreadATemplate<StoreMemoryOrder, LoadMemoryOrder>);
			auto thread2 = std::thread(ThreadBTemplate<StoreMemoryOrder, LoadMemoryOrder>);

			thread1.join();
			thread2.join();

			if (winner.load(std::memory_order_seq_cst) == 3) {
				ErrorCounter++;
			}
		}
		std::cout << "[" << LoadMemoryOrder << " " << StoreMemoryOrder << "] Error Num : " << ErrorCounter << std::endl;
	}

	void Main() {
		TestFuncTemplate<std::memory_order_relaxed, std::memory_order_relaxed>();
		TestFuncTemplate<std::memory_order_release, std::memory_order_acquire>();
		//TestFuncTemplate<std::memory_order_acq_rel, std::memory_order_acq_rel>(); 不知道为什么store的这个会报错，cppreference上面写是支持的。
		TestFuncTemplate<std::memory_order_seq_cst, std::memory_order_seq_cst>(); 
	}
}

// 伪共享测试
// UE里面检索这个false sharing也是很多例子的，伪共享对性能影响很大
namespace FalseSharingExample {
	// 用例参数配置
	constexpr long long ITERATIONS = 10000000;											// 迭代次数
#ifdef __cpp_lib_hardware_interference_size
	constexpr size_t CACHE_LINE_SIZE = std::hardware_destructive_interference_size;		// 在C++17中，标准库提供了这个常量，它就是专门用来避免伪共享的
#else
	constexpr size_t CACHE_LINE_SIZE = 64;												// 如果编译器不支持，我们手动定义为常见的64字节
#endif

	constexpr unsigned int MAX_THREAD = 32;												// 假设最多32个线程
	std::atomic<long long> counters_false_sharing[MAX_THREAD];							// 场景一：会产生伪共享的结构，多个原子变量紧密排列。
	std::atomic<long long>* GetAddressFake(unsigned int i) { return &counters_false_sharing[i]; }

	struct AlignedAtomic {																// 场景二：通过对齐和填充避免伪共享的结构
		alignas(CACHE_LINE_SIZE) std::atomic<long long> value = {0};					// alignas 强制该变量的起始地址按 CACHE_LINE_SIZE 对齐，这能确保 value 位于一个缓存行的开头
	};
	AlignedAtomic counters_aligned[MAX_THREAD];											// 对齐的数组，单个占用CACHE_LINE_SIZE大小
	std::atomic<long long>* GetAddressAligned(unsigned int i) { return &counters_aligned[i].value; }

	// 工作线程函数定义
	void ThreadFunc(std::atomic<long long>* counter) {
		for (long long i = 0; i < ITERATIONS; ++i) {
			counter->fetch_add(1, std::memory_order_relaxed);							// 使用 relaxed 内存序，因为我们这里不关心线程间同步，只关心原子操作本身的性能
		}
	}

	// 测试模板函数定义
	double TestFuncTemplate(const unsigned int num_threads, std::atomic<long long> *get_address(unsigned int)) {
		std::vector<std::thread> threads;

		auto start_time = std::chrono::high_resolution_clock::now();
		for (unsigned int i = 0; i < num_threads; ++i) {
			threads.emplace_back(ThreadFunc, get_address(i));
		}
		for (auto& t : threads) {
			t.join();
		}
		auto end_time = std::chrono::high_resolution_clock::now();

		// 检查
		for (unsigned int i = 0; i < num_threads; i++) {
			assert(get_address(i)->load(std::memory_order_relaxed) == ITERATIONS);
		}

		std::chrono::duration<double> duration = end_time - start_time;
		threads.clear();
		return duration.count();
	}

	void Main() {
		// 获取硬件支持的并发线程数
		const unsigned int num_threads = std::min<unsigned int>(MAX_THREAD, std::thread::hardware_concurrency());
		std::cout << "使用 "									<< num_threads		<< " 个线程进行测试"	<< std::endl;
		std::cout << "每次迭代 "								<< ITERATIONS		<< " 次"				<< std::endl;
		std::cout << "假定的缓存行大小 (Cache Line Size): "		<< CACHE_LINE_SIZE	<< " 字节"				<< std::endl;
		std::cout << "--------------------------------------"	<< std::endl;
		// --- 测试场景一：伪共享 ---
		std::cout << "场景一 (伪共享)   耗时: " << TestFuncTemplate(num_threads, GetAddressFake) << " 秒" << std::endl;	
		// --- 测试场景二：避免伪共享 ---
		std::cout << "场景二 (对齐解决) 耗时: " << TestFuncTemplate(num_threads, GetAddressAligned) << " 秒" << std::endl;
	}
}

#define RunNamespaceTest(NameSpace) { \
	using namespace NameSpace; \
	std::cout << "[Start test] " << #NameSpace << std::endl; \
	Main(); \
	std::cout << "[ End  test] " << #NameSpace << std::endl << std::endl; \
}

int main() {
	RunNamespaceTest(CountNumberExample);
	RunNamespaceTest(MemoryBarrierExample);
	RunNamespaceTest(MemoryOrderExample);
	RunNamespaceTest(FalseSharingExample);
}